/* Teach Tool  - Structural Dynamics
 * Copyright (C) 2009: Fabian Gerold, www.fabiangerold.de
 *
 * This file may be licensed under the terms of of the
 * GNU General Public License Version 3 (the "GPL").
 * 
 * Software distributed under the License is distributed 
 * on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either 
 * express or implied. See the GPL for the specific language 
 * governing rights and limitations.
 *
 * You should have received a copy of the GPL along with this 
 * program. If not, go to http://www.gnu.org/licenses/gpl.html
 * or write to the Free Software Foundation, Inc., 
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

#include "Diagram.h"
#include "System.h"

Diagram::Diagram( System* sys, QWidget *parent ) : m_system( sys), QWidget( parent )
{
	m_p = new QPainter;
	m_pixmap = new QPixmap( 3060, 200 );
	m_ex_path = new QPainterPath;
	m_h = 200;
	m_time = 100;
	m_scale = 1.0f;
	m_max_u = 0;
	m_max_up = 0;
	m_max_upp = 0;
	m_numpoints = 0;
	//m_numpoints_uc = 0;
	m_show_u = true;
	m_show_up = false;
	m_show_upp = false;
	paintInit();
	connect( m_system, SIGNAL( signalClearPoints() ),							this, SLOT( slotClearPoints() ) );
	connect( m_system, SIGNAL( signalDiagSetMax(float,float,float) ),			this, SLOT( slotSetMax(float,float,float) ) );
	connect( m_system, SIGNAL( signalDiagUpdate() ),							this, SLOT( slotUpdate() ) );
	connect( m_system, SIGNAL( signalDiagAddPoint(float,float,float,float) ),	this, SLOT( slotAddPoint(float,float,float,float) ) );
	connect( m_system, SIGNAL( signalDiagSetScale(float) ),						this, SLOT( slotSetScale(float) ) );
	connect( m_system, SIGNAL( signalSetExcitation(QPainterPath*,int) ),		this, SLOT( slotSetExcitation(QPainterPath*,int) ) );
}

void Diagram::slotSetMax( float u, float up, float upp )
{
	m_max_u = u>=0 ? u : -u;
	m_max_up = up>=0 ? up : -up;
	m_max_upp = upp>=0 ? upp : -upp;
	paintInit();
}

void Diagram::slotUpdate()
{
	update();
}

void Diagram::slotSetScale( float scale )
{
	if( scale >= 0.1 && scale <= 10 )
	{
		m_scale = scale;
	}
	totalRepaint();
}

void Diagram::slotClearPoints()
{
	m_time = 100;
	m_numpoints = 0;
	//m_numpoints_uc = 0;
	paintInit();
}


void Diagram::slotAddPoint( float time, float u, float up, float upp )
{
	if( m_numpoints >= 5000 ) return;
	//int dh = m_h - 30;
	m_time = time;

	m_points_u[m_numpoints] = QPointF( time*100, -u*100/m_max_u );
	m_points_up[m_numpoints] = QPointF( time*100, -up*100/m_max_up );
	m_points_upp[m_numpoints] = QPointF( time*100, -upp*100/m_max_upp );

	//m_u[m_numpoints] = -u*100/m_max_u;
	//m_up[m_numpoints] = -up*100/m_max_up;
	//m_upp[m_numpoints] = -upp*100/m_max_upp;

	m_numpoints++;
	if( m_numpoints < 2 ) return;

	m_p->begin( m_pixmap );
	m_p->setRenderHint( QPainter::Antialiasing );
	m_p->translate( 115, 5+(m_h-30)*0.5 );
	m_p->scale( m_scale, (m_h-30)*0.005 );

	// u
	if( m_show_u )
	{
		m_p->setPen( QColor( 93, 138, 93 ) );
		m_p->drawLine( m_points_u[m_numpoints-2], m_points_u[m_numpoints-1] );
		//m_p->drawLine( time*100-1, m_u[m_numpoints-2]-10, time*100, m_u[m_numpoints-1]-10 );
	}

	// up
	if( m_show_up )
	{
		m_p->setPen( QColor( 121, 139, 168 ) );
		m_p->drawLine( m_points_up[m_numpoints-2], m_points_up[m_numpoints-1] );
	}

	// upp
	if( m_show_upp )
	{
		m_p->setPen( QColor( 153, 117, 184 ) );
		m_p->drawLine( m_points_upp[m_numpoints-2], m_points_upp[m_numpoints-1] );
	}

	m_p->end();
}

void Diagram::slotSetExcitation( QPainterPath* path, int mode )
{
	m_ex_path->~QPainterPath();
	m_ex_path = path;

	m_mode = mode;

	paintInit();
}


void Diagram::totalRepaint()
{
	paintInit();
	m_p->begin( m_pixmap );
	m_p->setRenderHint( QPainter::Antialiasing );
	m_p->translate( 115, 5+(m_h-30)*0.5 );
	m_p->scale( m_scale, (m_h-30)*0.005 );

	// u
	if( m_show_u )
	{
		m_p->setPen( QColor( 93, 138, 93 ) );
		m_p->drawPolyline( m_points_u, m_numpoints );
	}

	// up
	if( m_show_up )
	{
		m_p->setPen( QColor( 121, 139, 168 ) );
		m_p->drawPolyline( m_points_up, m_numpoints );
	}

	// upp
	if( m_show_upp )
	{
		m_p->setPen( QColor( 153, 117, 184 ) );
		m_p->drawPolyline( m_points_upp, m_numpoints );
	}

	m_p->end();
	update();
}

void Diagram::showCurves( bool u, bool up, bool upp )
{
	m_show_u = u;
	m_show_up = up;
	m_show_upp = upp;
}

QSize Diagram::sizeHint() const
{
	return QSize( 3060, m_h );
}

QSize Diagram::minimumSizeHint() const
{
	return QSize( 3060, 200 );
}

void Diagram::resizeEvent( QResizeEvent * event )
{
	if( event->size().height() >= 200 )
	{
		m_h = event->size().height();
		setMinimumHeight( m_h );
		
		m_pixmap->~QPixmap();
		m_pixmap = new QPixmap( 3060, m_h );
		totalRepaint();
	}
	
	//int h = size().height();
	
}

void Diagram::paintInit()
{
	int dh = m_h - 30;
	m_p->begin( m_pixmap );
	
	m_p->setFont( QFont( "Arial", 8, QFont::Normal ) );

	m_p->setPen( QPen( QColor( 138, 183, 151 ) ) );
	m_p->fillRect( 0, 0, 3060, m_h, QBrush( QColor( 238, 238, 238 ) ) );


	// grid, horizontal
	m_p->setPen( QColor( 204, 204, 204 ) );
	for( int i=0; i<=10; ++i )
		m_p->drawLine( 115, 5+dh*i*0.1, 3060, 5+dh*i*0.1 );

	// grid, vertical
	//for( int i=0; i<20; ++i )
	//	m_p->drawLine( 115+i*m_scale*100, 5, 115+i*m_scale*100, 5+dh );
	
	int dx = 100*m_scale;
	float dt = 1;
	if( m_scale > 2 )
	{
		dx = 50*m_scale;
		dt = 0.5;
	}
	if( m_scale > 4 )
	{
		dx = 25*m_scale;
		dt = 0.25;
	}
	int x = 115;
	float t = 0;
	while( x <= 3060 )
	{
		m_p->setPen( QColor( 204, 204, 204 ) );
		m_p->drawLine( x, 5, x, 5+dh );

		m_p->setPen( QColor( 120, 120, 120 ) );
		m_p->drawText( x, 16+dh, QString::number( t ) );
		x += dx;
		t += dt;
	}

	//m_p->setPen( QColor( 120, 120, 120 ) );
	
	//for( int i=0; i<20; ++i )
		//m_p->drawText( 115+i*m_scale*100, 16+dh, QString::number( i ) );

	// main grid
        m_p->drawLine( QPointF( 115, 5+dh*0.5 ), QPointF( 3060, 5+dh*0.5 ) );
	m_p->drawLine( 115, 5, 115, 5+dh );
	
	// u
	m_p->setPen( QColor( 93, 138, 93 ) );
	for( int i=0; i<=10; ++i )
		m_p->drawText( 85, 10+dh*i*0.1, QString::number( int( (m_max_u*( 1 - float(i)/5.0 ))*100 )*0.01 ) );
	m_p->setRenderHint( QPainter::Antialiasing );
	
	// up
	m_p->setPen( QColor( 121, 139, 168 ) );
	for( int i=0; i<=10; ++i )
		m_p->drawText( 47, 10+dh*i*0.1, QString::number( int( (m_max_up*( 1 - float(i)/5.0 ))*100 )*0.01 ) );
	
	// up
	m_p->setPen( QColor( 153, 117, 184 ) );
	for( int i=0; i<=10; ++i )
		m_p->drawText( 5, 10+dh*i*0.1, QString::number( int( (m_max_upp*( 1 - float(i)/5.0 ))*100 )*0.01 ) );
	
	m_p->end();

	// now the excitation curve
	m_p->begin( m_pixmap );
	m_p->setRenderHint( QPainter::Antialiasing );
	m_p->translate( 115, 5+(m_h-30)*0.5 );
	m_p->scale( m_scale, (m_h-30)*0.005 );
	if( m_mode == 0 )
	{
		m_p->setPen( QColor( 153, 1, 1 ) );
		m_p->setBrush( QColor( 226, 195, 195 ) );
	}
	else
	{
		m_p->setPen( QColor( 72, 109, 151 ) );
		m_p->setBrush( QColor( 186, 195, 204 ) );
	}
	
	m_p->setOpacity( 0.3 );
	m_p->drawPath( *m_ex_path );
	m_p->end();
}

void Diagram::paintEvent( QPaintEvent* )
{
	m_p->begin( this );
	m_p->drawPixmap( 0, 0, *m_pixmap );
	
	// vertical line at the current time
	m_p->setPen( QColor( 200, 200, 200 ) );
	m_p->drawLine( 115+m_time*m_scale*100, 5, 115+m_time*m_scale*100, m_h-25 );
	m_p->end();
}
